#ifndef SEMINIX_BUG_H
#define SEMINIX_BUG_H

#include <seminix/types.h>

#define CUT_HERE		"------------[ cut here ]------------\n"

#ifndef __ASSEMBLY__

#include <seminix/printk.h>

#define MAYBE_BUILD_BUG_ON(cond)			\
    do {						\
        if (__builtin_constant_p((cond)))       \
            BUILD_BUG_ON(cond);             \
        else                                    \
            BUG_ON(cond);                   \
    } while (0)

#define BUG() do { \
    panic("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
    barrier_before_unreachable(); \
} while (0)

#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)

#define __WARN() do { \
    printk("WARNING: warn at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); } while (0)
#define __WARN_printk(arg...)	do { printk(arg); __WARN(); } while (0)

#define WARN_ON(condition) ({						\
    int __ret_warn_on = !!(condition);				\
    if (unlikely(__ret_warn_on))					\
        __WARN();						\
    unlikely(__ret_warn_on);					\
})

#define WARN(condition, format...) ({						\
    int __ret_warn_on = !!(condition);				\
    if (unlikely(__ret_warn_on))					\
        __WARN_printk(format);					\
    unlikely(__ret_warn_on);					\
})

#define WARN_ON_ONCE(condition)	({				\
    static bool __section(.data.once) __warned;		\
    int __ret_warn_once = !!(condition);			\
                                \
    if (unlikely(__ret_warn_once))				\
        if (WARN_ON(!__warned)) 			\
            __warned = true;			\
    unlikely(__ret_warn_once);				\
})

#define WARN_ONCE(condition, format...)	({			\
    static bool __section(.data.once) __warned;		\
    int __ret_warn_once = !!(condition);			\
                                \
    if (unlikely(__ret_warn_once))				\
        if (WARN(!__warned, format)) 			\
            __warned = true;			\
    unlikely(__ret_warn_once);				\
})

/*
 * Since detected data corruption should stop operation on the affected
 * structures. Return value must be checked and sanely acted on by caller.
 */
static inline bool check_data_corruption(bool v) { return v; }
#define CHECK_DATA_CORRUPTION(condition, fmt, ...)			 \
    check_data_corruption(({					 \
        bool corruption = unlikely(condition);			 \
        if (corruption) {					 \
            WARN(1, fmt, ##__VA_ARGS__);		 \
        }							 \
        corruption;						 \
    }))

#endif /* !__ASSEMBLY__ */
#endif /* !SEMINIX_BUG_H */
